package com.jiuan.retrofit.util

class Logger {
    companion object {
        private val V = "v"
        private val D = "d"
        private val I = "i"
        private val W = "w"
        private val E = "e"
        private val WTF = "wtf"
        private val MAX_LENGTH = 3000
        /**
         * Library debug tag.
         */
        private var STag = "Retrofit"
        /**
         * Library debug sign.
         */
        private var SDebug = false

        /**
         * Set tag of log.

         * @param tag tag.
         */
        fun setTag(tag: String) {
            STag = tag
        }

        /**
         * Open debug mode of `NoHttp`.

         * @param debug true open, false close.
         */
        fun setDebug(debug: Boolean) {
            SDebug = debug
        }

        fun i(msg: Any) {
            print(I, msg)
        }

        fun i(e: Throwable) {
            i(e, "")
        }

        fun i(e: Throwable, msg: Any) {
            print(I, msg, e)
        }

        fun v(msg: Any) {
            print(V, msg)
        }

        fun v(e: Throwable) {
            v(e, "")
        }

        fun v(e: Throwable, msg: Any) {
            print(V, msg, e)
        }

        fun d(msg: Any) {
            print(D, msg)
        }

        fun d(e: Throwable) {
            d(e, "")
        }

        fun d(e: Throwable, msg: Any) {
            print(D, msg, e)
        }

        fun e(msg: Any) {
            print(E, msg)
        }

        fun e(e: Throwable) {
            e(e, "")
        }

        fun e(e: Throwable, msg: String) {
            print(E, msg, e)
        }

        fun w(msg: String) {
            print(W, msg)
        }

        fun w(e: Throwable) {
            w(e, "")
        }

        fun w(e: Throwable, msg: String) {
            print(W, msg, e)
        }

        fun wtf(msg: String) {
            print(WTF, msg)
        }

        fun wtf(e: Throwable) {
            wtf(e, "")
        }

        fun wtf(e: Throwable, msg: String) {
            print(WTF, msg, e)
        }

        private fun print(method: String, o: Any) {
            print(method, STag, toString(o))
        }

        private fun toString(o: Any?): String {
            return o?.toString() ?: "null"
        }

        /**
         * Print log for define method. When information is too long, the Logger can also complete printing. The
         * equivalent of "`android.util.Log.i("Tag", "Message")`" "`Logger.print("i",
         * "Tag", "Message")`".

         * @param method  such as "`v, i, d, w, e, wtf`".
         * *
         * @param tag     tag.
         * *
         * @param message message.
         */
        private fun print(method: String, tag: String, message: String) {
            if (SDebug) {
                val strLength = message.length
                if (strLength == 0)
                    invokePrint(method, tag, message)
                else {
                    (0..strLength / MAX_LENGTH + (if (strLength % MAX_LENGTH > 0) 1 else 0) - 1)
                            .map { (it + 1) * MAX_LENGTH }
                            .forEach {
                                if (strLength >= it) {
                                    invokePrint(method, tag, message.substring(it - MAX_LENGTH, it))
                                } else {
                                    invokePrint(method, tag, message.substring(it - MAX_LENGTH))
                                }
                            }
                }
            }
        }

        /**
         * Through the reflection to call the print method.

         * @param method  such as "`v, i, d, w, e, wtf`".
         * *
         * @param tag     tag.
         * *
         * @param message message.
         */
        private fun invokePrint(method: String, tag: String, message: String) {
            try {
                val logClass = android.util.Log::class.java
                val logMethod = logClass.getMethod(method, String::class.java, String::class.java)
                logMethod.isAccessible = true
                logMethod.invoke(null, tag, message)
            } catch (e: Exception) {
                println(tag + ": " + message)
            }

        }

        /**
         * Print log for define method. When information is too long, the Logger can also complete printing. The
         * equivalent of "`android.util.Log.i("Tag", "Message")`" "`Logger.print("i",
         * "Tag", "Message")`".

         * @param method such as "`v, i, d, w, e, wtf`".
         * *
         * @param o      message.
         * *
         * @param e      error.
         */
        private fun print(method: String, o: Any, e: Throwable) {
            print(method, STag, toString(o), e)
        }

        /**
         * Print log for define method. When information is too long, the Logger can also complete printing. The
         * equivalent of "`android.util.Log.i("Tag", "Message")`" "`Logger.print("i",
         * "Tag", "Message")`".

         * @param method  such as "`v, i, d, w, e, wtf`".
         * *
         * @param tag     tag.
         * *
         * @param message message.
         * *
         * @param e       error.
         */
        private fun print(method: String, tag: String, message: String, e: Throwable) {
            invokePrint(method, tag, message, e)
        }

        /**
         * Through the reflection to call the print method.

         * @param method  such as "`v, i, d, w, e, wtf`".
         * *
         * @param tag     tag.
         * *
         * @param message message.
         * *
         * @param e       error.
         */
        private fun invokePrint(method: String, tag: String, message: String, e: Throwable) {
            if (SDebug)
                try {
                    val logClass = android.util.Log::class.java
                    val logMethod = logClass.getMethod(method, String::class.java, String::class.java, Throwable::class.java)
                    logMethod.isAccessible = true
                    logMethod.invoke(null, tag, message, e)
                } catch (e1: Exception) {
                    println(tag + ": " + message)
                }

        }
    }
}
